package edu.mcw.rgd.clinminer.security;

import java.util.Map;

import org.apache.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;

import edu.mcw.rgd.clinminer.security.Security.Roles;

@Aspect
@Configurable
@SuppressWarnings("unused")
public class AccessControl {
	private static final Logger log = Logger.getLogger(AccessControl.class);

	@Autowired
	private transient Security security;

	//
	// ACCESS POINTCUTS
	//

	@Pointcut("call (* listEntityViews()) && target(edu.mcw.rgd.clinminer.web.ClinminerEntityManagerView)")
	private void createMenu() {
	}

	@Around("createMenu()")
	public Object preFilterMenuCreation(ProceedingJoinPoint thisJoinPoint)
			throws Throwable {
		Map<String, Class> entityViews = (Map<String, Class>) thisJoinPoint
				.proceed();
		if (!security.isUserinRole(Roles.ROLE_CLINMINER_USER)) {
			log.debug("createMenu() - access denied for "
					+ security.getUsername() + " at "
					+ thisJoinPoint.getSignature().toShortString());
			entityViews.clear();
		}
		if (!security.isUserinRole(Roles.ROLE_CLINMINER_CURATOR)) {
			log.debug("createMenu() - access denied for Participant Details for "
					+ security.getUsername()
					+ " at "
					+ thisJoinPoint.getSignature().toShortString());
			entityViews.remove("Participant Details");
		}
		return entityViews;
	}

	@Pointcut("call (* org.vaadin.navigator.Navigator.*View(..))")
	private void navigationPointcut() {
	}

	// TODO protect details
	@Around("navigationPointcut()")
	public Object protectNavigate(ProceedingJoinPoint thisJoinPoint
			) throws Throwable {
		if (security.isUserinRole(Roles.ROLE_CLINMINER_USER)) {
			return thisJoinPoint.proceed();
		} else {
			log.debug("navigationPointcut() - access denied for "
					+ security.getUsername() + " at "
					+ thisJoinPoint.getSignature().toShortString() + " - "
					);
			return false;
		}
	}

	@Pointcut("execution(* is*Allowed())")
	private void writeOperation() {
	}

	/**
	 * WRITE (create update delete) pointcut security
	 */
	@Pointcut("within(edu.mcw.rgd.clinminer.web.ui.*)")
	private void viewLayer() {
	}

	/**
	 * Verifies that user has ROLE_CLINMINER_CURATOR role before they can write
	 * to database.
	 * 
	 * @param thisJoinPoint
	 * @return
	 * @throws Throwable
	 */
	@Around("viewLayer() && writeOperation()")
	public boolean preAuthorizeWrite(ProceedingJoinPoint thisJoinPoint)
			throws Throwable {
		if (security.isUserinRole(Roles.ROLE_CLINMINER_CURATOR)) {
			return (Boolean) thisJoinPoint.proceed();
		} else {
			log.debug("writeOperation() - access denied for "
					+ security.getUsername() + " at "
					+ thisJoinPoint.getSignature().toShortString());
			return false;
		}

	}

}
